/*	Copyright 2007 - Xavier Baro (xbaro@cvc.uab.cat)

	This file is part of eapmlib.

    Eapmlib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or any 
	later version.

    Eapmlib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "ThrClassifier.h"

// Temporal includes (must be replaced when dynamic object creation works)
#include "DissociatedDipole.h"

Evolutive::CThrClassifier::CThrClassifier(void):CClassifier(),m_Feature(NULL),m_Threshold(0.0),m_EqThrAction(EQTHR_ZERO),m_FeatureAux(NULL),m_Polarity(1)
{
#ifndef USE_OPENCV
	OPENCV_ERROR_CLASS("CThrClassifier");
#endif
}

Evolutive::CThrClassifier::~CThrClassifier(void)
{	
	if(m_FeatureAux)
		delete m_FeatureAux;
}

#ifdef USE_OPENCV
void Evolutive::CThrClassifier::SetFeature(CFeature *Feature)
{
	m_Feature=Feature;
}

void Evolutive::CThrClassifier::SetThreshold(double Threshold)
{
	m_Threshold=Threshold;
}

void Evolutive::CThrClassifier::SetThrEqualValueAction(Evolutive::THRCLASS_EQTHR Option)
{
	m_EqThrAction=Option;
}

void Evolutive::CThrClassifier::SetPolarity(int Polarity)
{
	m_Polarity=Polarity;
}

double Evolutive::CThrClassifier::Apply(CData *InputData)
{
	double Value;

	// check if the feature is available
	if(!m_Feature)
		throw CEvolutiveLibException("NULL feature",__FILE__,__LINE__,"Apply");	

	// Evaluate the feature
	Value=m_Feature->Apply(InputData);

	// Use the threshold value
	if(m_Polarity*Value<m_Threshold*m_Polarity)
		return -1.0;
	if(m_Polarity*Value>m_Threshold*m_Polarity)
		return 1.0;

	// Performs the defined action for the equality between the threshold and the value
	switch(m_EqThrAction)
	{
	case EQTHR_ZERO:
		return 0.0;
	case EQTHR_POS:
		return 1.0;
	case EQTHR_NEG:
		return -1.0;
	}

	// Accept the non decision value
	return 0.0;
}

void Evolutive::CThrClassifier::SetFeatureParameters(CChromosome *C)
{
	// check if the feature is available
	if(!m_Feature)
		throw CEvolutiveLibException("NULL feature",__FILE__,__LINE__,"SetFeatureParameters");

	// Modify the feature
	m_Feature->SetParameters(C);
}

void Evolutive::CThrClassifier::GetFeatureParameters(int &NumParameters,double **Parameters)
{
	// check if the feature is available
	if(!m_Feature)
		throw CEvolutiveLibException("NULL feature",__FILE__,__LINE__,"GetFeatureParameters");

	// check the pointer
	if(!Parameters)
		throw CEvolutiveLibException("NULL feature",__FILE__,__LINE__,"GetFeatureParameters");

	// Remove allocated memory
	if(Parameters[0])
		delete[] Parameters[0];

	// Assign the number of parameters of the feature
	NumParameters=m_Feature->GetNumParameters();

	// Allocate new memory
	Parameters[0]=new double[NumParameters];

	// Copy the parameters
	m_Feature->GetParameters(Parameters[0]);
}

bool Evolutive::CThrClassifier::IsValid(CChromosome *C)
{
	//! If there are no filter data 
	if(!m_FilterActive)
		return true;

	//! check if the feature is available
	if(!m_Feature)
		throw CEvolutiveLibException("NULL feature",__FILE__,__LINE__,"IsValid");

	//! Modify the feature
	m_Feature->SetParameters(C);

	//! Check if the feature is a valid feature
	return m_Feature->IsValid(m_ImageSize,m_UseColor);
}


Evolutive::CFeature* Evolutive::CThrClassifier::GetFeature(void)
{
	return m_Feature;
}

double Evolutive::CThrClassifier::GetThreshold(void)
{
	return m_Threshold;
}

void Evolutive::CThrClassifier::Serialize(std::fstream &fs,bool Saving)
{
	char Buffer [IO_CLASSNAME_LEN];

	// Call the base class method
	CClassifier::Serialize(fs,Saving);

	// Implement the specialized code
	if(Saving)
	{
		// Save the data to a file
		// Save the class attributes
		fs.write((char*)&m_Threshold,sizeof(double));
		fs.write((char*)&m_Polarity,sizeof(int));
		fs.write((char*)&m_EqThrAction,sizeof(THRCLASS_EQTHR));	

		// Save the class name of the feature
		strcpy(Buffer,m_Feature->GetClassNameID().data());
		fs.write((char*)Buffer,IO_CLASSNAME_LEN);

		// Launch the serialization method of the feature
		if(!m_Feature)
			throw CEvolutiveLibException("NULL feature",__FILE__,__LINE__,"Serialize");
		m_Feature->Serialize(fs,Saving);
	}
	else
	{
		// Load the data from a file
		// Load the class attributes
		fs.read((char*)&m_Threshold,sizeof(double));
		fs.read((char*)&m_Polarity,sizeof(int));
		fs.read((char*)&m_EqThrAction,sizeof(THRCLASS_EQTHR));			

		// Load the class name of the feature
		fs.read((char*)Buffer,IO_CLASSNAME_LEN);

		// Remove old self-created features
		if(m_FeatureAux)
			delete m_FeatureAux;		
		m_FeatureAux=NULL;

		// Create a new object of this class		
		if(!strcmp(Buffer,"CDissociatedDipole"))
		{
			m_FeatureAux=new CDissociatedDipole();						
		}
		
		// Check that the class name corresponds to some recognized class
		if(!m_FeatureAux)
			throw CEvolutiveLibException("Cannot create an instance of this class.",__FILE__,__LINE__,"Serialize");		

		m_Feature=m_FeatureAux;
		// TODO: Create this object without IF..THEN (LoadLibrary, dlopen, ...)

		// Launch the serialization method of the feature
		m_Feature->Serialize(fs,Saving);
	}
}
#endif //USE_OPENCV